/*
Copyright 2007 Raymond Giorgi

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */

package edu.pitt.CS2510.Nodes;

import java.util.ArrayList;

import edu.pitt.CS2510.Coordinate;
import edu.pitt.CS2510.Simulator;
import edu.pitt.CS2510.Grids.Grid;
import edu.pitt.CS2510.NodeActions.GruntActions;
import edu.pitt.CS2510.NodeActions.NodeActionsInterface;
import edu.pitt.CS2510.NodeActions.SupervisorActions;

/**
 * @author Alichino
 * 
 *         TODO To change the template for this generated type comment go to
 *         Window - Preferences - Java - Code Style - Code Templates
 */
public class WorkerNode extends Node {

	protected Simulator simulator;
	protected int id;
	protected WorkerNode type = null;
	protected Coordinate co = null;
	protected Coordinate enemyCo = null;
	protected int units;
	protected ArrayList<Integer> helpers = null;
	protected NodeActionsInterface messageHandler = null;
	public static int Supervisor = 1;
	public static int Grunt = 0;
	protected boolean requestedHelpers = false;
	private boolean finished = false;

	/**
	 * A connection to the simulator is required to send / recieve messages from
	 * other nodes.
	 * 
	 * @param simulator
	 * @param id
	 * @param grid
	 */
	public WorkerNode(Simulator simulator, int id, Grid grid) {
		super(simulator, grid);
		this.id = id;
		units = 10;
	}

	/**
	 * 
	 * @return the node's unique identification number
	 */
	public int getID() {
		return id;
	}

	/**
	 * Checks all the messages in the queue. If this is a Supervisor Node, check
	 * the enemy that's going to be attacked.
	 */
	@Override
	public void performAction() {
		processMessages();
		if (messageHandler instanceof SupervisorActions && !finished) {
			final int enemies = getEnemiesAtCo(enemyCo);
			int requested = 0;
			// If the task is too large and it has not already requested helpers
			if (enemies > 10 && !requestedHelpers) {
				requestedHelpers = true;
				int helpers = 0;
				int temp = enemies;
				// Request one helper for every 10 nodes past the first ten
				while (temp > 10 && requested < 4) {
					helpers++;
					temp -= 10;
					requested++;
				}
				((SupervisorActions) messageHandler)
						.sendRequestMessage(helpers);
			}
			// If the enemy has been defeated
			if (enemies <= 0) {
				((SupervisorActions) messageHandler)
						.sendQuitMessages(((SupervisorActions) messageHandler)
								.getHelpers());
				((SupervisorActions) messageHandler).sendDoneMessage();
				finished = true;
			}
		}
	}

	/**
	 * 
	 * @return the simulator.
	 */
	public Simulator getSimulator() {
		return simulator;
	}

	/**
	 * @return this node's unique id
	 */
	@Override
	public int getId() {
		return id;
	}

	protected void update(ArrayList list) {

	}

	/**
	 * if type is 0, this node will become a Grunt if type is 1, this node will
	 * become a Supervisor if type is -1, this node will become idle
	 * 
	 * @param type
	 */
	public void setType(int type) {
		if (type == 0) {
			messageHandler = new GruntActions(this);
		} else if (type == 1) {
			messageHandler = new SupervisorActions(this);
			helpers = new ArrayList<Integer>();
		} else if (type == -1) {
			messageHandler = null;
		}
	}

	/**
	 * Add the unique id of a grunt node that will act as a helper
	 * 
	 * @param node
	 */
	public void addGrunt(int node) {
		helpers.add(new Integer(node));
	}

	/**
	 * 
	 * @return the unique ids of all helpers
	 */
	public ArrayList<Integer> getHelpers() {
		return helpers;
	}

	/**
	 * this function is used to determine if the node is a Grunt or a Supervisor
	 * 
	 * @return the message handler
	 */
	@Override
	public NodeActionsInterface getMessageHandler() {
		return messageHandler;
	}

	/**
	 * This function used to do something. Not so much any more. If the
	 * programmer wants this node to contain units, this function will be useful
	 * 
	 * @deprecated
	 * @return
	 */
	public int getUnits() {
		return units;
	}

	/**
	 * This function used to do something. Not so much any more. If the
	 * programmer wants this node to contain units, this function will be
	 * useful.
	 * 
	 * @deprecated
	 */
	public void decrementUnits() {
		if (units > 0) {
			units--;
		} else {
			System.out.println("There are no more units left");
		}
	}

	/**
	 * This function used to do something. Not so much any more. If the
	 * programmer wants this node to contain units, this function will be
	 * useful.
	 * 
	 * @deprecated
	 */
	public void restoreUnits() {
		units = 10;
	}

	/**
	 * Set this node's placement in the grid
	 * 
	 * @param co
	 */
	public void setCoordinate(Coordinate co) {
		this.co = co;
	}

	/**
	 * 
	 * @return this node's placement in the grid
	 */
	public Coordinate getCoordinate() {
		return co;
	}

	public void release() {

	}

	/**
	 * Set the location of the enemy being attacked
	 * 
	 * @param co
	 */
	public void setEnemy(Coordinate co) {
		enemyCo = co;
	}

	/**
	 * @return the location of the enemy being attacked
	 */
	public Coordinate getEnemy() {
		return enemyCo;
	}
}